home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / DT_UTIL.PY < prev    next >
Encoding:
Python Source  |  2000-07-05  |  18.1 KB  |  536 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64. '''$Id: DT_Util.py,v 1.66.10.3 2000/07/05 15:54:20 shane Exp $''' 
  65. __version__='$Revision: 1.66.10.3 $'[11:-2]
  66.  
  67. import regex, string, math, os
  68. from string import strip, join, atoi, lower, split, find
  69. import VSEval
  70.  
  71. str=__builtins__['str'] # Waaaaa, waaaaaaaa needed for pickling waaaaa
  72.  
  73. ParseError='Document Template Parse Error'
  74. ValidationError='Unauthorized'
  75.  
  76.  
  77. def html_quote(v, name='(Unknown name)', md={},
  78.                character_entities=(
  79.                        (('&'),    '&'),
  80.                        (('<'),    '<' ),
  81.                        (('>'),    '>' ),
  82.                        (('\213'), '<' ),
  83.                        (('\233'), '>' ),
  84.                        (('"'),    '"'))): #"
  85.         text=str(v)
  86.         for re,name in character_entities:
  87.             if find(text, re) >= 0: text=join(split(text,re),name)
  88.         return text
  89.  
  90. def int_param(params,md,name,default=0, st=type('')):
  91.     try: v=params[name]
  92.     except: v=default
  93.     if v:
  94.         try: v=atoi(v)
  95.         except:
  96.             v=md[v]
  97.             if type(v) is st: v=atoi(v)
  98.     return v or 0
  99.  
  100. _marker=[]
  101.  
  102. def careful_getattr(md, inst, name, default=_marker):
  103.     
  104.     if name[:1]!='_':
  105.  
  106.         # Try to get the attribute normally so that we don't
  107.         # accidentally acquire when we shouldn't.
  108.         try: v=getattr(inst, name)
  109.         except:
  110.             if default is not _marker:
  111.                 return default
  112.             raise
  113.  
  114.         validate=md.validate
  115.  
  116.         if validate is None: return v
  117.  
  118.         if hasattr(inst,'aq_acquire'):
  119.             return inst.aq_acquire(name, validate, md)
  120.  
  121.         if validate(inst,inst,name,v,md): return v
  122.  
  123.     raise ValidationError, name
  124.  
  125. def careful_hasattr(md, inst, name):
  126.     v=getattr(inst, name, _marker)
  127.     if v is not _marker:
  128.         try: 
  129.             if name[:1]!='_':
  130.                 validate=md.validate                
  131.                 if validate is None: return 1
  132.     
  133.                 if hasattr(inst,'aq_acquire'):
  134.                     inst.aq_acquire(name, validate, md)
  135.                     return 1
  136.     
  137.                 if validate(inst,inst,name,v,md): return 1
  138.         except: pass
  139.     return 0
  140.  
  141. def careful_getitem(md, mapping, key):
  142.     v=mapping[key]
  143.  
  144.     if type(v) is type(''): return v # Short-circuit common case
  145.  
  146.     validate=md.validate
  147.     if validate is None or validate(mapping,mapping,None,v,md): return v
  148.     raise ValidationError, key
  149.  
  150. def careful_getslice(md, seq, *indexes):
  151.     v=len(indexes)
  152.     if v==2:
  153.         v=seq[indexes[0]:indexes[1]]
  154.     elif v==1:
  155.         v=seq[indexes[0]:]
  156.     else: v=seq[:]
  157.  
  158.     if type(seq) is type(''): return v # Short-circuit common case
  159.  
  160.     validate=md.validate
  161.     if validate is not None:
  162.         for e in v:
  163.             if not validate(seq,seq,None,e,md):
  164.                 raise ValidationError, 'unauthorized access to slice member'
  165.  
  166.     return v
  167.  
  168. def careful_range(md, iFirst, *args):
  169.     # limited range function from Martijn Pieters
  170.     RANGELIMIT = 1000
  171.     if not len(args):
  172.         iStart, iEnd, iStep = 0, iFirst, 1
  173.     elif len(args) == 1:
  174.         iStart, iEnd, iStep = iFirst, args[0], 1
  175.     elif len(args) == 2:
  176.         iStart, iEnd, iStep = iFirst, args[0], args[1]
  177.     else:
  178.         raise AttributeError, 'range() requires 1-3 int arguments'
  179.     if iStep == 0: raise ValueError, 'zero step for range()'
  180.     iLen = int((iEnd - iStart) / iStep)
  181.     if iLen < 0: iLen = 0
  182.     if iLen >= RANGELIMIT: raise ValueError, 'range() too large'
  183.     return range(iStart, iEnd, iStep)
  184.  
  185. import string, math, whrandom
  186.  
  187. try:
  188.     import ExtensionClass
  189.     from cDocumentTemplate import InstanceDict, TemplateDict, render_blocks
  190. except: from pDocumentTemplate import InstanceDict, TemplateDict, render_blocks
  191.  
  192.  
  193. d=TemplateDict.__dict__
  194. for name in ('None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int',
  195.              'len', 'max', 'min', 'oct', 'ord', 'round', 'str'):
  196.     d[name]=__builtins__[name]
  197. d['string']=string
  198. d['math']=math
  199. d['whrandom']=whrandom
  200.  
  201. def careful_pow(self, x, y, z):
  202.     if not z: raise ValueError, 'pow(x, y, z) with z==0'
  203.     return pow(x,y,z)
  204.  
  205. d['pow']=careful_pow
  206.  
  207. try:
  208.     import random
  209.     d['random']=random
  210. except: pass
  211.  
  212. try:
  213.     import DateTime
  214.     d['DateTime']=DateTime.DateTime
  215. except: pass
  216.  
  217. def test(self, *args):
  218.     l=len(args)
  219.     for i in range(1, l, 2):
  220.         if args[i-1]: return args[i]
  221.  
  222.     if l%2: return args[-1]
  223.  
  224. d['test']=test
  225.  
  226. def obsolete_attr(self, inst, name, md):
  227.     return careful_getattr(md, inst, name)
  228.  
  229. d['attr']=obsolete_attr
  230. d['getattr']=careful_getattr
  231. d['hasattr']=careful_hasattr
  232. d['range']=careful_range
  233.  
  234. #class namespace_:
  235. #    __allow_access_to_unprotected_subobjects__=1
  236.  
  237. def namespace(self, **kw):
  238.     """Create a tuple consisting of a single instance whose attributes are
  239.     provided as keyword arguments."""
  240.     if type(self) != TemplateDict:
  241.         raise TypeError,'''A call was made to DT_Util.namespace() with an
  242.         incorrect "self" argument.  It could be caused by a product which
  243.         is not yet compatible with this version of Zope.  The traceback
  244.         information may contain more details.'''
  245.     return apply(self, (), kw)
  246.  
  247. d['namespace']=namespace
  248.  
  249. def render(self, v, simple={
  250.     type(''): 1, type(0): 1, type(0.0): 1,
  251.     type([]): 1, type(()): 1,
  252.     }.has_key):
  253.     "Render an object in the way done be the 'name' attribute"
  254.  
  255.     if not simple(type(v)):
  256.         if hasattr(v,'isDocTemp') and v.isDocTemp:
  257.             v=v(None, self)
  258.         else:
  259.             try: v=v()
  260.             except (AttributeError,TypeError): pass
  261.     return v
  262.  
  263. d['render']=render
  264.  
  265. def reorder(self, s, with=None, without=()):
  266.     if with is None: with=s
  267.     d={}
  268.     tt=type(())
  269.     for i in s:
  270.         if type(i) is tt and len(i)==2: k, v = i
  271.         else:                           k= v = i
  272.         d[k]=v
  273.     r=[]
  274.     a=r.append
  275.     h=d.has_key
  276.  
  277.     for i in without:
  278.         if type(i) is tt and len(i)==2: k, v = i
  279.         else:                           k= v = i
  280.         if h(k): del d[k]
  281.         
  282.     for i in with:
  283.         if type(i) is tt and len(i)==2: k, v = i
  284.         else:                           k= v = i
  285.         if h(k):
  286.             a((k,d[k]))
  287.             del d[k]
  288.  
  289.     return r
  290.  
  291. d['reorder']=reorder
  292.  
  293.  
  294. expr_globals={
  295.     '__builtins__':{},
  296.     '__guarded_mul__':      VSEval.careful_mul,
  297.     '__guarded_getattr__':  careful_getattr,
  298.     '__guarded_getitem__':  careful_getitem,
  299.     '__guarded_getslice__': careful_getslice,
  300.     }
  301.  
  302. class Eval(VSEval.Eval):
  303.     
  304.     def eval(self, mapping):
  305.         d={'_vars': mapping, '_': mapping}
  306.         code=self.code
  307.         globals=self.globals
  308.         for name in self.used:
  309.             __traceback_info__ = name
  310.             try: d[name]=mapping.getitem(name,0)
  311.             except KeyError:
  312.                 if name=='_getattr':
  313.                     d['__builtins__']=globals
  314.                     exec compiled_getattr in d
  315.  
  316.         return eval(code,globals,d)
  317.  
  318.  
  319. def name_param(params,tag='',expr=0, attr='name', default_unnamed=1):
  320.     used=params.has_key
  321.     __traceback_info__=params, tag, expr, attr
  322.  
  323.     #if expr and used('expr') and used('') and not used(params['']):
  324.     #   # Fix up something like: <!--#in expr="whatever" mapping-->
  325.     #   params[params['']]=default_unnamed
  326.     #   del params['']
  327.         
  328.     if used(''):
  329.         v=params['']
  330.  
  331.         if v[:1]=='"' and v[-1:]=='"' and len(v) > 1: # expr shorthand
  332.             if used(attr):
  333.                 raise ParseError, ('%s and expr given' % attr, tag)
  334.             if expr:
  335.                 if used('expr'):
  336.                     raise ParseError, ('two exprs given', tag)
  337.                 v=v[1:-1]
  338.                 try: expr=Eval(v, expr_globals)
  339.                 except SyntaxError, v:
  340.                     raise ParseError, (
  341.                         '<strong>Expression (Python) Syntax error</strong>:'
  342.                         '\n<pre>\n%s\n</pre>\n' % v[0],
  343.                         tag)
  344.                 return v, expr
  345.             else: raise ParseError, (
  346.                 'The "..." shorthand for expr was used in a tag '
  347.                 'that doesn\'t support expr attributes.',
  348.                 tag)
  349.  
  350.         else: # name shorthand            
  351.             if used(attr):
  352.                 raise ParseError, ('Two %s values were given' % attr, tag)
  353.             if expr:
  354.                 if used('expr'):
  355.                     # raise 'Waaaaaa', 'waaa'
  356.                     raise ParseError, ('%s and expr given' % attr, tag)
  357.                 return params[''],None
  358.             return params['']
  359.  
  360.     elif used(attr):
  361.         if expr:
  362.             if used('expr'):
  363.                 raise ParseError, ('%s and expr given' % attr, tag)
  364.             return params[attr],None
  365.         return params[attr]
  366.     elif expr and used('expr'):
  367.         name=params['expr']
  368.         expr=Eval(name, expr_globals)
  369.         return name, expr
  370.         
  371.     raise ParseError, ('No %s given' % attr, tag)
  372.  
  373. Expr_doc="""
  374.  
  375.  
  376. Python expression support
  377.  
  378.   Several document template tags, including 'var', 'in', 'if', 'else',
  379.   and 'elif' provide support for using Python expressions via an
  380.   'expr' tag attribute.
  381.  
  382.   Expressions may be used where a simple variable value is
  383.   inadequate.  For example, an expression might be used to test
  384.   whether a variable is greater than some amount::
  385.  
  386.      <!--#if expr="age > 18"-->
  387.  
  388.   or to transform some basic data::
  389.  
  390.      <!--#var expr="phone[:3]"-->
  391.  
  392.   Objects available in the document templates namespace may be used.
  393.   Subobjects of these objects may be used as well, although subobject
  394.   access is restricted by the optional validation method.
  395.  
  396.   In addition, a special additional name, '_', is available.  The '_'
  397.   variable provides access to the document template namespace as a
  398.   mapping object.  This variable can be useful for accessing objects
  399.   in a document template namespace that have names that are not legal
  400.   Python variable names::
  401.   
  402.      <!--#var expr="_['sequence-number']*5"-->
  403.   
  404.   This variable also has attributes that provide access to standard
  405.   utility objects.  These attributes include:
  406.   
  407.   - The objects: 'None', 'abs', 'chr', 'divmod', 'float', 'hash',
  408.        'hex', 'int', 'len', 'max', 'min', 'oct', 'ord', 'pow',
  409.        'round', and 'str' from the standard Python builtin module.
  410.  
  411.   - Special security-aware versions of 'getattr' and 'hasattr',
  412.   
  413.   - The Python 'string', 'math', and 'whrandom' modules, and
  414.   
  415.   - A special function, 'test', that supports if-then expressions.
  416.     The 'test' function accepts any number of arguments.  If the
  417.     first argument is true, then the second argument is returned,
  418.     otherwise if the third argument is true, then the fourth
  419.     argument is returned, and so on.  If there is an odd number of
  420.     arguments, then the last argument is returned in the case that
  421.     none of the tested arguments is true, otherwise None is
  422.     returned. 
  423.   
  424.   For example, to convert a value to lower case::
  425.   
  426.     <!--#var expr="_.string.lower(title)"-->
  427.  
  428. """
  429.  
  430. ListType=type([])
  431. def parse_params(text,
  432.                  result=None,
  433.                  tag='',
  434.                  unparmre=regex.compile(
  435.                      '\([\0- ]*\([^\0- =\"]+\)\)'),
  436.                  qunparmre=regex.compile(
  437.                      '\([\0- ]*\("[^"]*"\)\)'),
  438.                  parmre=regex.compile(
  439.                      '\([\0- ]*\([^\0- =\"]+\)=\([^\0- =\"]+\)\)'),
  440.                  qparmre=regex.compile(
  441.                      '\([\0- ]*\([^\0- =\"]+\)="\([^"]*\)\"\)'),
  442.                  **parms):
  443.  
  444.     """Parse tag parameters
  445.  
  446.     The format of tag parameters consists of 1 or more parameter
  447.     specifications separated by whitespace.  Each specification
  448.     consists of an unnamed and unquoted value, a valueless name, or a
  449.     name-value pair.  A name-value pair consists of a name and a
  450.     quoted or unquoted value separated by an '='.
  451.  
  452.     The input parameter, text, gives the text to be parsed.  The
  453.     keyword parameters give valid parameter names and default values.
  454.  
  455.     If a specification is not a name-value pair and it is not the
  456.     first specification and it is a
  457.     valid parameter name, then it is treated as a name-value pair with
  458.     a value as given in the keyword argument.  Otherwise, if it is not
  459.     a name-value pair, it is treated as an unnamed value.
  460.  
  461.     The data are parsed into a dictionary mapping names to values.
  462.     Unnamed values are mapped from the name '""'.  Only one value may
  463.     be given for a name and there may be only one unnamed value. """
  464.  
  465.     result=result or {}
  466.  
  467.     if parmre.match(text) >= 0:
  468.         name=lower(parmre.group(2))
  469.         value=parmre.group(3)
  470.         l=len(parmre.group(1))
  471.     elif qparmre.match(text) >= 0:
  472.         name=lower(qparmre.group(2))
  473.         value=qparmre.group(3)
  474.         l=len(qparmre.group(1))
  475.     elif unparmre.match(text) >= 0:
  476.         name=unparmre.group(2)
  477.         l=len(unparmre.group(1))
  478.         if result:
  479.             if parms.has_key(name):
  480.                 if parms[name] is None: raise ParseError, (
  481.                     'Attribute %s requires a value' % name, tag)
  482.                     
  483.                 result[name]=parms[name]
  484.             else: raise ParseError, (
  485.                 'Invalid attribute name, "%s"' % name, tag)
  486.         else:
  487.             result['']=name
  488.         return apply(parse_params,(text[l:],result),parms)
  489.     elif qunparmre.match(text) >= 0:
  490.         name=qunparmre.group(2)
  491.         l=len(qunparmre.group(1))
  492.         if result: raise ParseError, (
  493.             'Invalid attribute name, "%s"' % name, tag)
  494.         else: result['']=name
  495.         return apply(parse_params,(text[l:],result),parms)
  496.     else:
  497.         if not text or not strip(text): return result
  498.         raise ParseError, ('invalid parameter: "%s"' % text, tag)
  499.     
  500.     if not parms.has_key(name):
  501.         raise ParseError, (
  502.             'Invalid attribute name, "%s"' % name, tag)
  503.  
  504.     if result.has_key(name):
  505.         p=parms[name]
  506.         if type(p) is not ListType or p:
  507.             raise ParseError, (
  508.                 'Duplicate values for attribute "%s"' % name, tag)
  509.             
  510.     result[name]=value
  511.  
  512.     text=strip(text[l:])
  513.     if text: return apply(parse_params,(text,result),parms)
  514.     else: return result
  515.